import { Grid } from './grid';
import { Tile } from './tile';
/*
  1.网格，方块
  2.方块选中状态，最多点2块，超过2块，取消选中
  3.连线规则：直线连接(覆盖连接最小显示)，边界连线(空白连接), 折角连接（若无直线，不超两个折角才可以连接），所有连接线都不能穿过其他图案
  4.消除机制：完成连线规则的两个方块会在棋盘上消除
  5.时间规则: 规定时间内完成消除，时间到，游戏结束，timeLimit：限时，elapsedTime：玩家实际用时。
  7.分数系统: 基础分const baseScore = pairsCleared * 2;每消除一对加2分
  score = baseScore + (timeLimit - elapsedTime)
*/

enum GameState {
  PRELOAD = 'preload',
  START = 'start',
  RUNNING = 'running',
  PAUSE = 'pause',
  OVER = 'over',
  RESTART = 'restart',
}

export interface GameStateObject {
  level: number;
  score: number;
  time: number;
  over: boolean;
  grid: any;
  // hintCount: number;//提示次数
  state: GameState;
}

export class GameManager {
  // 管理器相关
  storageManager: any;
  inputManager: any;
  actuator: any;
  // 游戏相关
  grid: Grid | null = null; // 游戏网格
  animationFrameId: any;
  timeLimit: number = 900 * 1000; // 游戏时间限制（秒）15分钟
  curTime: number = 0; // 游戏当前时间（秒）
  score: number = 0; // 游戏得分
  level: number = 0; // 等级,后续会根据不同等级初始化游戏
  over: boolean = false; // 游戏是否结束
  curState: GameState = GameState.PRELOAD; //默认预加载
  selectedTile: Tile | null = null;
  isRemove: boolean = true; //是否可以消除,用来测试

  constructor(inputManager: any, actuator: any, storage: any) {
    this.storageManager = storage;
    this.inputManager = inputManager;
    this.actuator = actuator;
    this.inputManager.on("select", this.selectTile.bind(this));//将 GameManager 类的 move 方法绑定到 inputManager 对象的 "move" 事件上
    this.setup();
  }

  restart() {
    this.storageManager.clearGameState();
    this.setup();
  }

  setup() {
    const previousState = this.storageManager.getGameState();
    if (previousState) {
      this.grid = new Grid(previousState.grid.cells); // Reload grid
      this.score = previousState.score;
      this.level = previousState.level;
      this.curState = previousState.state;
      this.curTime = previousState.time;
    } else {
      this.grid = new Grid();
      this.score = 0;
      this.level = 0;
      this.curState = GameState.START;
      this.curTime = this.timeLimit;
    }
    // console.log(this.grid);
    // 更新页面和持久化状态
    this.actuate();
    this.startTimer();
  }

  startTimer() {
    const self = this;
    this.animationFrameId = requestAnimationFrame(() => {
      this.curTime--;
      self.actuator.updateTime(self.curTime)
      this.startTimer();
    });
  }
  stopTimer() {
    if (this.animationFrameId !== null) {
      cancelAnimationFrame(this.animationFrameId);
      this.animationFrameId = null;
    }
  }
  //更新游戏状态和持久化
  actuate() {
    if (this.over) {
      this.storageManager.clearGameState();
    } else {
      this.storageManager.setGameState(this.serialize());
    }
    this.actuator.actuate(this.grid, {
      score: this.score,
      over: this.over,
      time: this.curTime,
    });
  }
  serialize() {
    const temp = this.grid?.serialize();
    const removeOver = temp?.left_tile_num == 0
    const timeOver = this.curTime == 0
    this.over = removeOver || timeOver
    if (this.over) {
      this.stopTimer()
    }
    return {
      grid: temp,
      score: this.score,
      time: this.curTime,
      over: this.over,
      level: this.level,
      state: this.curState,
    } as GameStateObject;
  }
  selectTile(position: { x: number; y: number; }) {
    // console.log('选中', position);
    if (!this.selectedTile) {
      // 第一次选择
      this.selectedTile = this.grid?.cellContent(position);
      if (this.selectedTile) {
        this.selectedTile.setLight();
        this.actuator.updateTile([this.selectedTile]);
      }
    } else {
      // 第二次选择
      const firstTile = this.selectedTile;
      const secondTile = this.grid?.cellContent(position);
      if (secondTile) {
        secondTile.setLight();
        this.actuator.updateTile([secondTile]);
      }
      let isDisappear = false//是否满足消除规则
      // 检查是否有可消除的组合
      if (this.checkMatches(firstTile, secondTile)) {
        const ways = this.getPath(firstTile, secondTile)
        if (ways.length) {
          // 连线绘制
          this.actuator.drawLine(ways)
          isDisappear = true
        }
      }
      if (isDisappear && this.isRemove) {
        //延迟隐藏消除
        const timer = setTimeout(() => {
          this.removeTiles([firstTile, secondTile])
          clearTimeout(timer)
        }, 500);
      } else {
        firstTile.clearLight();
        secondTile.clearLight();
        this.actuator.updateTile([firstTile, secondTile]);
      }
      this.selectedTile = null;

    }
    // console.log(this.isConnectWithTwoTurns(2, 4, 0, 1));
  }

  updateScore(): void {
    this.score = this.score + 10;
    this.actuator.updateScore(this.score);
  }
  updateIsRemove(isRemove: boolean) {
    this.isRemove = isRemove
  }

  removeTiles(tiles: Tile[]): void {
    const self = this;
    tiles.forEach(tile => {
      self?.grid?.removeTile(tile);
    });
    // 更新分数没消除一对获取10分
    self.updateScore();
    this.actuate();
  }
  checkMatches(firstTile: Tile, secondTile: Tile): boolean {
    if (firstTile.value !== secondTile.value) {
      return false;
    } else {
      return true;
    }
  }
  // 获取两点之间路径，并返回
  getPath(firstTile: Tile, secondTile: Tile): any[] {
    const self = this;
    console.log('getPath', firstTile, secondTile);
    const startX = firstTile.x;
    const startY = firstTile.y;
    const endX = secondTile.x;
    const endY = secondTile.y;
    const isSameSide = startX === endX || startY === endY
    if (self.grid?.isOnBoundary(firstTile) && self.grid?.isOnBoundary(secondTile) && isSameSide) {
      // 在边缘并同边
      return [{ x: startX, y: startY }, { x: endX, y: endY }]

    } else {
      let searchPath: { ways: any[], isPath: boolean } = self.isConnectStraight(startX, startY, endX, endY)
      console.log('isConnectStraight', searchPath);
      if (searchPath.isPath) {
        return searchPath.ways
      } else {
        searchPath = self.isConnectWithOneTurn(startX, startY, endX, endY)
        console.log('isConnectWithOneTurn', searchPath);
        if (searchPath.isPath) {
          return searchPath.ways
        } else {
          searchPath = self.isConnectWithTwoTurns(startX, startY, endX, endY)
          console.log('isConnectWithTwoTurns', searchPath);
          if (searchPath.isPath) {
            return searchPath.ways
          } else {
            return []
          }
        }
      }
    }
  }
  // 判断直线连线：检查是否同行同列，连线上没有其他方块
  isConnectStraight(startX: number, startY: number, endX: number, endY: number): { ways: any[], isPath: boolean } {
    const self = this;
    let ways = [];
    // 检查是否相邻
    const isNextX = startX === endX && Math.abs(startY - endY) === 1
    const isNextY = startY === endY && Math.abs(startX - endX) === 1
    console.log({ startX, startY }, { endX, endY }, isNextX, isNextY);
    if (isNextX || isNextY) {
      return {
        ways: [
          { x: startX, y: startY },
          { x: endX, y: endY },
        ],
        isPath: true
      };
    }
    if (startX === endX) {
      // 同一列
      const step = startY < endY ? 1 : -1;
      ways.push({ x: startX, y: startY });
      // 结束条件
      const over = (y: number) => {
        if (startY < endY) {
          return y < endY
        } else {
          return y > endY
        }
      }
      for (let y = startY + step; over(y); y += step) {
        // console.log('startX === endX', { x: startX, y });
        if (self.grid?.cellContent({ x: startX, y })) {
          return {
            ways: [],
            isPath: false // 路径上存在其他方块
          }
        }
        try {
          ways.push({ x: startX, y });
        } catch (error) {
          console.log(error);
        }
      }
      ways.push({ x: endX, y: endY });
      return {
        ways,
        isPath: true // 路径上不存在其他方块
      }
    } else if (startY === endY) {
      // 同一行
      const step = startX < endX ? 1 : -1;
      ways.push({ x: startX, y: startY });
      // 结束条件
      const over = (x: number) => {
        if (startX < endX) {
          return x < endX
        } else {
          return x > endX
        }
      }
      for (let x = startX + step; over(x); x += step) {
        if (self.grid?.cellContent({ x, y: startY })) {
          return {
            ways: [],
            isPath: false // 路径上存在其他方块
          }
        }
        ways.push({ x, y: startY });
      }
      ways.push({ x: endX, y: endY });
      return {
        ways,
        isPath: true // 路径上不存在其他方块
      }
    } else {
      return {
        ways: [],
        isPath: false
      }
    }
  }
  // 判断单折线连线
  isConnectWithOneTurn(startX: number, startY: number, endX: number, endY: number): { ways: any[], isPath: boolean } {
    const self = this;
    if (!self.grid) {
      return {
        ways: [],
        isPath: false
      }
    }

    let ways: any[] = [];
    console.log('----------------开始判断单折-----------------');
    console.log('第一个折点', { x: startX, y: endY }, self.grid.cellContent({ x: startX, y: endY }));

    if (!self.grid.cellContent({ x: startX, y: endY })) {
      // 第一个折点判断 self.grid.cellContent({ x: startX, y: endY })
      const searchPath1: { ways: any[], isPath: boolean } = self.isConnectStraight(startX, startY, startX, endY)
      console.log('从 [startX, startY] 到 [startX, endY]', { startX, startY }, { startX, endY }, searchPath1);
      // 从 [startX, endY 到 [endX, endY]
      const searchPath2: { ways: any[], isPath: boolean } = self.isConnectStraight(startX, endY, endX, endY)
      console.log('从 [startX, endY] 到 [endX, endY]', { startX, endY }, { endX, endY }, searchPath2);
      if (searchPath1.isPath && searchPath2.isPath) {
        const merged = [...searchPath1.ways, ...searchPath2.ways];
        const unique = [...new Map(merged.map(item => [JSON.stringify(item), item])).values()];
        ways = unique;
      }
    }
    console.log('第二个折点', { x: endX, y: startY }, self.grid.cellContent({ x: endX, y: startY }));
    if (!self.grid.cellContent({ x: endX, y: startY })) {
      // 第二个折点判断self.grid.cellContent({ x: endX, y: startY })
      const searchPath1: { ways: any[], isPath: boolean } = self.isConnectStraight(startX, startY, endX, startY)
      console.log('从 [startX, startY] 到 [endX, startY]', { startX, startY }, { endX, startY }, searchPath1);
      // 从 [startX, endY 到 [endX, endY]
      const searchPath2: { ways: any[], isPath: boolean } = self.isConnectStraight(endX, startY, endX, endY)
      console.log('从 [endX, startY] 到 [endX, endY]', { endX, startY }, { endX, endY }, searchPath2);
      if (searchPath1.isPath && searchPath2.isPath) {
        const merged = [...searchPath1.ways, ...searchPath2.ways];
        const unique = [...new Map(merged.map(item => [JSON.stringify(item), item])).values()];
        ways = unique;
      }
    }

    console.log('-----------------结束判断单折-----------------');
    return {
      ways,
      isPath: ways.length > 0
    }
  }
  // 判断双折点连线
  isConnectWithTwoTurns(startX: number, startY: number, endX: number, endY: number): { ways: any[], isPath: boolean } {
    const self = this;
    if (!self.grid) {
      return {
        ways: [],
        isPath: false
      }
    }

    let ways: any[] = [];
    ways.push({ x: startX, y: startY })
    for (let y = -1; y <= self.grid._col_size; y++) {
      if (!self.grid.cellContent({ x: startX, y })) {
        const path1 = self.isConnectStraight(startX, startY, startX, y);
        const path2 = self.isConnectWithOneTurn(startX, y, endX, endY);
        if (path1.isPath && path2.isPath) {
          console.log(startX, y);
          ways.push(...path1.ways, ...path2.ways);
          const unique = [...new Map(ways.map(item => [JSON.stringify(item), item])).values()];//去重
          ways = unique
          break;
        }
      }
    }

    console.log('垂直', ways);

    if (ways.length == 1) {
      // 表示垂直方向没有满足路线
      // 水平
      for (let x = -1; x <= self.grid._row_size; x++) {
        if (!self.grid.cellContent({ x, y: startY })) {
          console.log('+++++++++++++++++++++++', startX, startY, x, startY, endX, endY);
          const path1 = self.isConnectStraight(startX, startY, x, startY);
          const path2 = self.isConnectWithOneTurn(x, startY, endX, endY);
          console.log('path1', path1, 'path2', path2);

          if (path1.isPath && path2.isPath) {
            console.log(x, startY);
            ways.push(...path1.ways, ...path2.ways);
            const unique = [...new Map(ways.map(item => [JSON.stringify(item), item])).values()];//去重
            ways = unique
            break;
          }
        }
      }
      console.log('水平', ways);
    }

    return {
      ways: ways.length > 1 ? ways : [],
      isPath: ways.length > 1
    }
  }
  exit() {
    console.log('退出游戏');

  }

}